#include <nxos.h>

#define DRV_NAME "test driver"
#define DEV0_NAME "udriver_test0"
#define DEV1_NAME "udriver_test1"

NX_PRIVATE NX_Error TestOpen(struct NX_Device *device, NX_U32 flags)
{
    NX_Printf("test open dev:%s flags:%x\n", device->name, flags);
    return NX_EOK;
}

NX_PRIVATE NX_Error TestClose(struct NX_Device *device)
{
    NX_Printf("test close dev:%s\n", device->name);
    return NX_EOK;
}

NX_PRIVATE NX_Error TestRead(struct NX_Device *device, void *buf, NX_Offset off, NX_Size len, NX_Size *outLen)
{
    NX_Printf("test read dev:%s buf:%p off:%d len:%d out:%p\n", device->name, buf, off, len, outLen);

    char * newbuf = NX_DriverRemapBuf(buf, len);
    NX_Size * newOutLen = NX_DriverRemapBuf(outLen, sizeof(NX_Size));

    NX_Printf("new buf:%p out:%p\n", newbuf, newOutLen);

    int i;
    for (i = 0; i < len; i++)
    {
        newbuf[i] = i;
    }

    *newOutLen = len;

    return NX_EOK;
}

NX_PRIVATE NX_Error TestWrite(struct NX_Device *device, void *buf, NX_Offset off, NX_Size len, NX_Size *outLen)
{
    NX_Printf("test write dev:%s buf:%p off:%d len:%d out:%p\n", device->name, buf, off, len, outLen);

    char * newbuf = NX_DriverRemapBuf(buf, len);
    NX_Size * newOutLen = NX_DriverRemapBuf(outLen, sizeof(NX_Size));

    NX_Printf("new buf:%p out:%p\n", newbuf, newOutLen);

    int i;
    for (i = 0; i < len; i++)
    {
        NX_Printf("dev write: %x\n", newbuf[i]);
    }
    NX_Printf("\n");

    *newOutLen = len;

    return NX_EOK;
}

NX_PRIVATE NX_Error TestControl(struct NX_Device *device, NX_U32 cmd, void *arg)
{
    NX_Printf("test control dev:%s cmd:%x arg:%p\n", device->name, cmd, arg);
    return NX_EOK;
}

NX_PRIVATE NX_Error TestMappable(struct NX_Device *device, NX_Size length, NX_U32 prot, NX_Addr * outPhyAddr)
{
    NX_Printf("test mappable dev:%s len:%d prot:%x out phy addr\n", device->name, length, prot, outPhyAddr);
    return NX_ENORES;
}

NX_PRIVATE NX_DriverOps TestDriverOps = {
    .open = TestOpen,
    .close = TestClose,
    .read = TestRead,
    .write = TestWrite,
    .control = TestControl,
    .mappable = TestMappable,
};

NX_Error TEST_Udriver(char *cmdline)
{
    NX_Device *device;
    NX_Solt driverSolt;
    NX_Driver *driver = NX_DriverCreate(DRV_NAME, NX_DEVICE_TYPE_VIRT, 0, &TestDriverOps);
    if (driver == NX_NULL)
    {
        NX_Printf("create driver failed!\n");
        return NX_ERROR;
    }

    if (NX_DriverAttachDevice(driver, DEV0_NAME, &device) != NX_EOK)
    {
        NX_Printf("attach device %s failed!\n", DEV0_NAME);
        NX_DriverDestroy(driver);
        return NX_ERROR;
    }

    if (NX_DriverAttachDevice(driver, DEV1_NAME, &device) != NX_EOK)
    {
        NX_Printf("attach device %s failed!\n", DEV1_NAME);
        NX_DriverDetachDevice(driver, DEV0_NAME);
        NX_DriverDestroy(driver);
        return NX_ERROR;
    }

    if ((driverSolt = NX_DriverRegister(driver)) == NX_SOLT_INVALID_VALUE)
    {
        NX_Printf("register driver %s failed!\n", DRV_NAME);
        NX_DriverDetachDevice(driver, DEV0_NAME);
        NX_DriverDetachDevice(driver, DEV1_NAME);
        NX_DriverDestroy(driver);
        return NX_ERROR;
    }
    
    NX_Printf("register driver %s success!\n", DRV_NAME);

    NX_DriverRun(driverSolt, driver);

    NX_Printf("driver %s run over!\n", DRV_NAME);

    return NX_EOK;
}
